package utils

import (
	"errors"
	"fmt"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/util/gconv"
	"github.com/gomodule/redigo/redis"
	"math/rand"
	"time"
)

const (
	URL_STATUS_UNCRAWLED   = 10
	URL_STATUS_CRAWLED     = 1
	URL_STATUS_FAIL        = 2
	URL_STATUS_PROCESSING  = 3
	PORT_LIST_REDIS        = "web_driver_port"
	JCJY_RESULT_REDIS      = "jcjy_result"
	CG99_TOPIC_REDIS       = "cg99_result"
	LINKABLE_ACCOUNT_REDIS = "linkable_account"
	FIRST_LEVEL_URL        = "first_level_url"
	SECOND_LEVEL_URL       = "second_level_url"

	LINKABLE_ARTICLE = "linkable_article"
)

func RedisSetItemStatus(url string, status int) {

	conn := g.Redis().Conn()
	defer conn.Close()
	conn.Do("SET", url, status)
}

func RedisGetItemStatus(url string) (int, error) {
	conn := g.Redis().Conn()
	defer conn.Close()
	val, err := conn.DoVar("GET", url)
	if err != nil {
		return -1, err
	}
	return val.Int(), nil
}

func initRedisPort() {
	conn := g.Redis().Conn()
	defer conn.Close()

	arPort := make([]interface{}, 0)

	startPort := g.Cfg().GetInt("chromedriver.taskport_start")

	arPort = append(arPort, PORT_LIST_REDIS)

	for i := 0; i < 100; i++ {
		port := i + startPort
		portstr := gconv.String(port)
		arPort = append(arPort, portstr)
	}
	_, err := conn.Do("LPUSH", arPort...)
	if err != nil {
		fmt.Println("init port reids fail : ", err)
	}
	return

}

func RedisGetValidPort() int {
	conn := g.Redis().Conn()
	defer conn.Close()

	v, err := conn.Do("EXISTS", PORT_LIST_REDIS)
	if err != nil {
		return -1
	}
	if gconv.Int(v) == 0 {
		initRedisPort()
	}

	v, err = conn.Do("LPOP", PORT_LIST_REDIS)
	if err != nil {
		return -1
	}
	str := gconv.String(v)
	return gconv.Int(str)
}

func RedisReleasePort(port int) {
	conn := g.Redis().Conn()
	defer conn.Close()
	_, err := conn.Do("RPUSH", PORT_LIST_REDIS, gconv.String(port))
	if err != nil {
		fmt.Println("RedisReleasePort fail ", err)
	}
}

func SetAccountToRedis(email string, content string) {
	conn := g.Redis().Conn()
	defer conn.Close()
	conn.Do("HSET", LINKABLE_ACCOUNT_REDIS, email, content)
}

func DelAccountFromRedis(email string) {
	conn := g.Redis().Conn()
	defer conn.Close()
	conn.Do("HDEL", LINKABLE_ACCOUNT_REDIS, email)
}

func SetAccountCookieToRedis(email string, content string) {
	conn := g.Redis().Conn()
	defer conn.Close()
	conn.Do("HSET", LINKABLE_ACCOUNT_REDIS, email, content)
}

func GetAccountCookieFromRedis(email string) (string, error) {
	conn := g.Redis().Conn()
	defer conn.Close()
	val, err := conn.DoVar("HGET", LINKABLE_ACCOUNT_REDIS, email)
	if err != nil {
		return "", err
	}
	return val.String(), nil
}

func GetRandomAccountCookieFromRedis() (string, error) {
	conn := g.Redis().Conn()
	defer conn.Close()

	keys, err := redis.Strings(conn.Do("HKEYS", LINKABLE_ACCOUNT_REDIS))
	if err != nil {
		return "", err
	}

	if len(keys) == 0 {
		return "", errors.New("No accounts found in Redis")
	}

	rand.Seed(time.Now().UnixNano())
	randomIndex := rand.Intn(len(keys))
	email := keys[randomIndex]

	val, err := redis.String(conn.Do("HGET", LINKABLE_ACCOUNT_REDIS, email))
	if err != nil {
		return "", err
	}

	return val, nil
}

func SetFirstLevelUrlToRedis(url string, content string) {
	conn := g.Redis().Conn()
	defer conn.Close()
	conn.Do("HSET", FIRST_LEVEL_URL, url, content)
}

func GetFirstLevelAllUrlFromRedis() (map[string]string, error) {
	conn := g.Redis().Conn()
	defer conn.Close()
	values, err := redis.StringMap(conn.Do("HGETALL", FIRST_LEVEL_URL))
	if err != nil {
		return nil, err
	}
	return values, nil
}

func SetDownloadUrlToRedis(url string, content string) {
	conn := g.Redis().Conn()
	defer conn.Close()
	conn.Do("HSET", SECOND_LEVEL_URL, url, content)
}

func GetDownloadUrlFromRedis(url string) ([]string, error) {
	conn := g.Redis().Conn()
	defer conn.Close()
	values, err := redis.Strings(conn.Do("HGET", SECOND_LEVEL_URL, url))
	if err != nil {
		return nil, err
	}
	return values, nil
}
func SetArticleToRedis(url string, content string) {
	conn := g.Redis().Conn()
	defer conn.Close()
	conn.Do("HSET", LINKABLE_ARTICLE, url, content)
}

func GetArticleFromRedis(url string) (string, error) {
	conn := g.Redis().Conn()
	defer conn.Close()
	val, err := conn.DoVar("HGET", LINKABLE_ARTICLE, url)
	if err != nil {
		return "", err
	}
	return val.String(), nil
}
